<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style rel="stylesheet">
        html,
        body {
            -ms-touch-action: none;
            -ms-content-zooming: none;
            position: absolute;
            margin: 0;
            padding: 0;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background: #222;
        }
        #screen {
            position: absolute;
            left: 50%;
            top: 50%;
            background: #000;
            overflow: hidden;
            width: 400px;
            height: 400px;
            margin-left: -200px;
            margin-top: -200px;
        }
        #canvas {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
<div id="screen">
    <canvas id="canvas"></canvas>
</div>
</body>
</html>
<script>
    var ge1doot = ge1doot || {
                screen: {
                    elem: null,
                    callback: null,
                    ctx: null,
                    width: 0,
                    height: 0,
                    left: 0,
                    top: 0,
                    init: function(id, callback, initRes) {
                        this.elem = document.getElementById(id);
                        this.callback = callback || null;
                        if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
                        window.addEventListener('resize', function() {
                            this.resize();
                        }.bind(this), false);
                        this.elem.onselectstart = function() {
                            return false;
                        }
                        this.elem.ondrag = function() {
                            return false;
                        }
                        initRes && this.resize();
                        return this;
                    },
                    resize: function() {
                        var o = this.elem;
                        this.width = o.offsetWidth;
                        this.height = o.offsetHeight;
                        for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
                            this.left += o.offsetLeft;
                            this.top += o.offsetTop;
                        }
                        if (this.ctx) {
                            this.elem.width = this.width;
                            this.elem.height = this.height;
                        }
                        this.callback && this.callback();
                    },
                    pointer: {
                        screen: null,
                        elem: null,
                        callback: null,
                        pos: {
                            x: 0,
                            y: 0
                        },
                        drag: {
                            x: 0,
                            y: 0
                        },
                        start: {
                            x: 0,
                            y: 0
                        },
                        end: {
                            x: 0,
                            y: 0
                        },
                        active: false,
                        down: function(e, touch) {
                            e.preventDefault();
                            var pointer = touch ? e.touches[0] : e;
                            (!touch && document.setCapture) && document.setCapture();
                            this.pos.x = this.start.x = pointer.clientX - this.screen.left;
                            this.pos.y = this.start.y = pointer.clientY - this.screen.top;
                            this.active = true;
                            this.callback.down && this.callback.down();
                        },
                        up: function(e, touch) {
                            e.preventDefault();
                            (!touch && document.releaseCapture) && document.releaseCapture();
                            this.end.x = this.drag.x;
                            this.end.y = this.drag.y;
                            this.active = false;
                            this.callback.up && this.callback.up();
                        },
                        move: function(e, touch) {
                            e.preventDefault();
                            if (this.active) {
                                var pointer = touch ? e.touches[0] : e;
                                this.pos.x = pointer.clientX - this.screen.left;
                                this.pos.y = pointer.clientY - this.screen.top;
                                this.drag.x = this.end.x - (this.pos.x - this.start.x);
                                this.drag.y = this.end.y - (this.pos.y - this.start.y);
                                this.callback.move && this.callback.move();
                            }
                        },
                        init: function(callback) {
                            this.screen = ge1doot.screen;
                            this.elem = this.screen.elem;
                            this.callback = callback || {};
                            if ('ontouchstart' in window) {
                                // touch
                                this.elem.ontouchstart = function(e) {
                                    this.down(e, true);
                                }.bind(this);
                                this.elem.ontouchmove = function(e) {
                                    this.move(e, true);
                                }.bind(this);
                                this.elem.ontouchend = function(e) {
                                    this.up(e, true);
                                }.bind(this);
                                this.elem.ontouchcancel = function(e) {
                                    this.up(e, true);
                                }.bind(this);
                            }
                            // mouse
                            document.addEventListener("mousedown", function(e) {
                                this.down(e, false);
                            }.bind(this), true);
                            document.addEventListener("mousemove", function(e) {
                                this.move(e, false);
                            }.bind(this), true);
                            document.addEventListener("mouseup", function(e) {
                                this.up(e, false);
                            }.bind(this), true);
                            return this;
                        }
                    },
                    loadImages: function(container) {
                        var elem = document.getElementById(container),
                                canvas = document.createElement('canvas'),
                                ctx,
                                init = false,
                                complete = false,
                                n = document.images.length;

                        function arc(color, val, r) {
                            ctx.beginPath();
                            ctx.moveTo(50, 50);
                            ctx.arc(50, 50, r, 0, val);
                            ctx.fillStyle = color;
                            ctx.fill();
                            ctx.closePath();
                        }

                        function load() {
                            if (complete) {
                                canvas.style.display = "none";
                                return;
                            }
                            var m = 0,
                                    timer = 32;
                            for (var i = 0; i < n; i++) m += (document.images[i].complete) ? 1 : 0;
                            if (m < n) {
                                if (!init) {
                                    init = true;
                                    canvas.style.width = canvas.style.height = "100px";
                                    canvas.width = canvas.height = 100;
                                    canvas.style.position = "fixed";
                                    canvas.style.left = canvas.style.top = "50%";
                                    canvas.style.marginTop = canvas.style.marginLeft = "-50px";
                                    canvas.style.zIndex = 10000;
                                    ctx = canvas.getContext("2d");
                                    arc('rgb(64,64,64)', Math.PI * 2, 48);
                                    elem.appendChild(canvas);
                                }
                                arc('rgb(255,255,255)', (m / n) * 2 * Math.PI, 50);
                            } else {
                                if (init) {
                                    arc('rgb(255,255,255)', 2 * Math.PI, 50);
                                    timer = 300;
                                }
                                complete = true;
                            }
                            setTimeout(load, timer);
                        }
                        setTimeout(load, 32);
                    }
                }
            }

    ! function() {
        "use strict";

        var screen = ge1doot.screen.init("screen", null, true);
        var ctx = screen.ctx;
        var pointer = screen.pointer.init({
            move: fire,
            down: fire
        });
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var sw = canvas.width = screen.width;
        var sh = canvas.height = screen.height;
        var ram = new Uint32Array(sw * sh);

        var fires = [],
                maxFires = 400,
                nFire = 0;
        // ==== write FIRE ====
        ctx.font = "bold 60px arial";
        ctx.fillStyle = "rgba(255,255,255,1)";
        ctx.fillText("手拉手", 10, 320);
        var img = ctx.getImageData(0, 0, sw, sh);
        var bytes = img.data;
        for (var i = 0; i < sh; i += 8) {
            for (var j = 0; j <= sw; j += 8) {
                if (bytes[(i * sw + j) * 4] != 0) {
                    if (nFire < maxFires) {
                        fires[nFire++] = [i * 1, j * 1]
                    }
                }
            }
        }
        nFire = 0;
        // ==== scale main canvas ====
        var scale = 4;
        ctx.scale(scale, scale);
        sw /= scale
        sh /= scale
        // ==== buffer ====
        var bufferImage = document.createElement('canvas');
        bufferImage.width = sw;
        bufferImage.height = sh;
        var ict = bufferImage.getContext('2d');
        var img = ict.createImageData(sw, sh);
        var bytes = img.data;
        // ==== add more fire ====
        function fire() {
            fires[nFire++] = [pointer.pos.y, pointer.pos.x];
            if (nFire > maxFires) nFire = 0;
        }
        // ==== main loop ====
        function run() {
            requestAnimationFrame(run);
            // ==== maintain fire ====
            for (var i = 0; i < maxFires; i++) {
                if (fires[i]) {
                    var k = (Math.round(fires[i][0] / scale) * sw + Math.round(fires[i][1] / scale));
                    ram[k] = 1024;
                }
            }
            // ==== render fire ====
            for (var i = 0; i < sh; i++) {
                for (var j = 0; j <= sw; j++) {
                    var p = i * sw + j;
                    var ap = p + sw - (0.5 + Math.random() | 0);
                    var nc = ((ram[ap] || 0) + (ram[ap + 1] || 0) + (ram[ap + sw] || 0) + (ram[ap - sw + 1] || 0)) * 0.24;
                    ram[p] = nc;
                    var k = p * 4;
                    bytes[k] = nc;
                    bytes[k + 1] = nc / 3;
                    bytes[k + 3] = 255;
                }
            }
            ict.putImageData(img, 0, 0);
            ctx.drawImage(bufferImage, 0, 0);
        }
        // ==== start animation ====
        requestAnimationFrame(run);

    }();
</script>